package com.springboot.frame.web.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * request工具类
 *
 * @author gsl
 */
@Slf4j
public final class RequestUtils {

    private RequestUtils() {
    }

    /**
     * 获取当前服务器访问url
     *
     * @param request 请求
     * @return url
     */
    public static String getServerUrl(HttpServletRequest request) {
        return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
                + request
                .getContextPath();
    }

    /**
     * 获取当前 URL 包含查询条件
     *
     * @param charset URLEncoder编码格式
     */
    public static String getQueryString(HttpServletRequest request, Charset charset) {
        StringBuilder sb = new StringBuilder(request.getRequestURL());
        String query = request.getQueryString();
        if (query != null && query.length() > 0) {
            sb.append("?").append(query);
        }
        try {
            return URLEncoder.encode(sb.toString(), charset.name());
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

    /**
     * url是否在请求内
     *
     * @param request 请求
     * @param url     参数为以';'分割的URL字符串
     * @return 是否存在
     */
    public static boolean containUrl(HttpServletRequest request, String url) {
        boolean result = false;
        if (url != null && !"".equals(url.trim())) {
            String[] urlArr = url.split(";");
            StringBuilder reqUrl = new StringBuilder(request.getRequestURL());
            for (String anUrlArr : urlArr) {
                if (reqUrl.indexOf(anUrlArr) > 1) {
                    result = true;
                    break;
                }
            }
        }
        return result;
    }

    /**
     * 获取当前完整请求地址
     *
     * @return 请求地址
     */
    public static String getRequestUrl(HttpServletRequest request) {
        StringBuilder url = new StringBuilder(request.getScheme())
                .append("://")
                .append(request.getHeader("host"))
                .append(request.getRequestURI());
        if (request.getQueryString() != null) {
            url.append("?").append(request.getQueryString());
        }
        return url.toString();
    }

    /**
     * 获取Request PlayLoad 内容
     *
     * @return Request PlayLoad 内容
     */
    public static String requestPlayLoad(HttpServletRequest request) throws IOException {
        try (InputStream inputStream = request.getInputStream();
             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
            StringBuilder sb = new StringBuilder();
            char[] charBuffer = new char[128];
            int bytesRead;
            while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                sb.append(charBuffer, 0, bytesRead);
            }
            return sb.toString();
        }
    }


    /**
     * 获取请求basePath
     */
    public static String getBasePath(HttpServletRequest request) {
        StringBuffer basePath = new StringBuffer();
        String scheme = request.getScheme();
        String domain = request.getServerName();
        int port = request.getServerPort();
        basePath.append(scheme);
        basePath.append("://");
        basePath.append(domain);
        if ("http".equalsIgnoreCase(scheme) && 80 != port) {
            basePath.append(":").append(String.valueOf(port));
        } else if ("https".equalsIgnoreCase(scheme) && port != 443) {
            basePath.append(":").append(String.valueOf(port));
        }
        return basePath.toString();
    }

    /**
     * 根据流接收请求数据
     *
     * @param request
     * @return
     */
    public static String streamBodyByReceive(HttpServletRequest request) throws IOException {
        log.info("   回调地址：{}", request.getRequestURL());
        StringBuffer buffer = new StringBuffer();
        InputStream inputStream = request.getInputStream();
        InputStreamReader reader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(reader);
        String body = null;
        while ((body = bufferedReader.readLine()) != null) {
            buffer.append(body);
        }
        String data = buffer.toString();
        reader.close();
        inputStream.close();
        log.info("   回调参数：{}", data);
        return data;
    }

    /**
     * 一个简单的签名认证，规则：
     * 1. 将请求参数按ascii码排序
     * 2. 拼接为a=value&b=value...这样的字符串（不包含sign）
     * 3. 混合密钥（secret）进行md5获得签名，与请求的签名进行比较
     *
     * secret 秘钥
     */
    private boolean validateSign(HttpServletRequest request,String secret) {
        String requestSign = request.getParameter("sign");//获得请求签名，如sign=19e907700db7ad91318424a97c54ed57
        if (StringUtils.isEmpty(requestSign)) {
            return false;
        }
        List<String> keys = new ArrayList<String>(request.getParameterMap().keySet());
        keys.remove("sign");//排除sign参数
        Collections.sort(keys);//排序

        StringBuilder sb = new StringBuilder();
        for (String key : keys) {
            sb.append(key).append("=").append(request.getParameter(key)).append("&");//拼接字符串
        }
        String linkString = sb.toString();
        linkString = StringUtils.substring(linkString, 0, linkString.length() - 1);//去除最后一个'&'
        String sign = DigestUtils.md5Hex(linkString + secret);//混合密钥md5

        return StringUtils.equals(sign, requestSign);//比较
    }
}
